昨天主要提到一些共用的頁面和模組,今天來看看 VueUse API 頁面的文件是怎麼透過 VitePress 設定的。
樣式設定的部分,主要是 import 到 .vitepress/theme/index.ts
,原始碼位置:https://github.com/vueuse/vueuse/blob/main/packages/.vitepress/theme/index.ts
其中一個程式碼片段:
import './styles/main.css'
import './styles/demo.css'
import './styles/utils.css'
import './styles/vars.css'
import './styles/overrides.css'
import 'uno.css'
除了 uno.css
,引入的 css 檔案都放在 .vitepress/theme/styles
這個目錄中。跟 VitePress 文件中的說明一樣。
另外 VueUse 的 Demo 有用到 UnoCSS 的 class,所以來看一下要怎麼在 VitePress 中設定 UnoCSS。
VitePress 的設定檔:https://github.com/vueuse/vueuse/blob/main/packages/.vitepress/config.ts#L250
vite: viteConfig
其中有這個跟 Vite 相關的設定,接著找到 viteConfig:https://github.com/vueuse/vueuse/blob/main/packages/.vitepress/vite.config.ts
設定的方式跟一般在 Vue 專案中使用 UnoCSS 是一樣的。
因為我的目標是要復刻 VueUse 文件,所以實作就直接複製需要的樣式與設定,像是 unocss.config.ts
就直接搬來用,還有 .vitepress/theme/styles
裡面的幾支檔案也是。
這邊放上我實作的簡易版本,因為沒有要用到 PWA 跟其他設定,所以單純很多:
// projects/.vitepress/config.mjs
import UnoCSS from 'unocss/vite'
import { defineConfig } from 'vitepress'
export default defineConfig({
base: '/rhino-notebook/',
title: 'Rhino Notebook',
description: 'Rhino Notebook',
themeConfig: {
// ...略
},
vite: {
plugins: [
UnoCSS(),
],
},
})
昨天最後有提到 VueUse Functions 頁面是由 FunctionsList 這個組件做呈現的,這個組件跟其他 theme component 一樣都放在這個位置:https://github.com/vueuse/vueuse/tree/main/packages/.vitepress/theme/components
我目前有用到 BooleanDisplay.vue
、DemoContainer.vue
、Note.vue
這三個。
VueUse 有針對 theme component 做 auto import 的設定,舉例來說,我們來看 useScreenOrientation 的 Demo:
// packages/core/useScreenOrientation/demo.vue
<script setup lang="ts">
import { useScreenOrientation } from '.'
const { isSupported, orientation, angle } = useScreenOrientation()
</script>
<template>
<note class="mb-2">
For best results, please use a mobile or tablet device (or use your browser's native inspector to simulate an
orientation change)
</note>
<div>
isSupported: <boolean-display :value="isSupported">
{{ isSupported }}
</boolean-display>
</div>
<div>Orientation Type: <b>{{ orientation }}</b></div>
<div>Orientation Angle: <b>{{ angle }}</b></div>
</template>
會發現 note 這個組件在最上方沒有 import,可以直接使用。
auto import 跟之前提到的 UnoCSS 一樣,都是用 vite plugin 的方式做設定:https://github.com/vueuse/vueuse/blob/main/packages/.vitepress/vite.config.ts#L36 ,看一下原始碼的這個片段:
import Components from 'unplugin-vue-components/vite'
import { resolve } from 'node:path'
// ... 略
// plugins
Components({
dirs: resolve(__dirname, 'theme/components'),
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
resolvers: [
IconsResolver({
componentPrefix: '',
}),
],
dts: resolve(__dirname, 'components.d.ts'),
transformer: 'vue3',
}),
這邊需要額外安裝 unplugin-vue-components 這個套件。
以 useMouse 的官方 Demo 為例,畫面上有 x
、y
、sourceType
,這些在原始碼中,本來是一個 reactive 的物件,最後被轉換為 YAML 格式,變成我們看到的樣子,來看一下官方 Demo 的程式碼片段:
<script setup lang="ts">
import type { UseMouseEventExtractor } from '@vueuse/core'
import { useMouse, useParentElement } from '@vueuse/core'
import { stringify } from '@vueuse/docs-utils'
import { reactive } from 'vue'
const parentEl = useParentElement()
const mouseDefault = reactive(useMouse())
const textDefault = stringify(mouseDefault)
const extractor: UseMouseEventExtractor = (event) => {
if (typeof Touch !== 'undefined' && event instanceof Touch)
return null
else
return [event.offsetX, event.offsetY]
}
const mouseWithExtractor = reactive(useMouse({ target: parentEl, type: extractor }))
const textWithExtractor = stringify(mouseWithExtractor)
</script>
<template>
<p>Basic Usage</p>
<pre lang="yaml">{{ textDefault }}</pre>
<p>Extractor Usage</p>
<pre lang="yaml">{{ textWithExtractor }}</pre>
</template>
stringify
的原始碼位置放在 .vitepress/plugins 的目路中:https://github.com/vueuse/vueuse/blob/main/packages/.vitepress/plugins/utils.ts
裡面有用到 reactify
這個方法,這個跟 VitePress 比較無關就先不細看,看起來是在轉換成 YAML 的同時,也必須保持響應性,這樣我們在跟 Demo 畫面互動的時候,才能看到即時更新的數值。
先貼上我實作的版本,一樣用 useMouse 當範例,以下是 useMouse 的 index.md:
---
category: Sensors
---
# useMouse
Reactive mouse position
## Demo
<script setup>
import Demo from './demo.vue'
</script>
This is a .md using a custom component
<DemoContainer>
<Demo />
</DemoContainer>
## Basic Usage
// ... 略
部署到線上的部落格:https://rhinolee.github.io/rhino-notebook/front-end/vueuse/core/useMouse/
畫面上 Demo 的部分跟 VueUse 長得差不多。
接著來看 VueUse useMouse index.md 的原始碼:
---
category: Sensors
---
# useMouse
Reactive mouse position
## Basic Usage
// ... 略
這裡並沒有引入 Demo.vue,也沒有使用 <Demo />
把 Demo 組件放到畫面上,那為什麼畫面上一樣會出現 Demo 區塊?
後來看原始碼發現這邊客製化了一個 Plugin,先看設定的最源頭:https://github.com/vueuse/vueuse/blob/main/packages/.vitepress/vite.config.ts#L31
可以看到在 Vite plugins 中設定了 MarkdownTransform()
,MarkdownTransform
的原始碼位置:https://github.com/vueuse/vueuse/blob/main/packages/.vitepress/plugins/markdownTransform.ts
其中用到了 getFunctionMarkdown
這個 function,其中有一段就包含剛剛在找的 Demo Section。
如果使用我的版本,那每個文件檔的 Markdown 都需要引入 Demo 並使用它,這部分不像其他描述部分會變動,Demo 這個區塊的寫法都一樣,很適合做自動化。看原始碼也會發現 VueUse API 文件下方的 Contributors
、Changelog
也都是用自動化的方式實現,不會出在每個文件 Markdown 中。
我的 VitePress GitHub repository:https://github.com/RhinoLee/rhino-notebook
我的 VitePress Demo:https://rhinolee.github.io/rhino-notebook/front-end/vueuse/core/useMouseInElement/
這兩天大概看了一下 VueUse 是怎麼透過 VitePress 這套工具生成官方文件的,並實作了一個自己的版本,但現在上面只有復刻 VueUse 的東西,連主題色都一起仿冒過去了 XD,這部分之後會做一些調整。
最後面有看到 VueUse 是怎麼透過客製 Plugin ,來處理一些適合被自動化的區塊,這個未來應該會用到,到時候再回來更詳細的研究。另外 YAML 那招滿好用的,比起直接顯示物件格式,用 YAML 格式好看很多。
VitePress 相關的原始碼就到這邊告一段落~